package com.tiancheng.trade.order.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.web.http.PlatformRequest;
import com.tiancheng.trade.commom.core.data.PageInfo;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.ArgumentErrorInfoEnum;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.order.enums.ReportChannelEnum;
import com.tiancheng.trade.order.mapper.ReportChannelMapper;
import com.tiancheng.trade.order.model.ReportChannel;
import com.tiancheng.trade.order.model.ReportChannelConfig;
import com.tiancheng.trade.order.model.ReportRecord;
import com.tiancheng.trade.order.service.IReportRecordService;
import com.tiancheng.trade.order.service.ReportChannelConfigService;
import com.tiancheng.trade.order.service.ReportChannelService;
import com.tiancheng.trade.order.util.CommonUtil;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.order.util.cache.ReportCache;
import com.tiancheng.trade.order.mq.MessageProducer;
import com.tiancheng.trade.order.vo.admin.QueryReportChannelVO;
import com.tiancheng.trade.order.vo.app.ChannelReportCacheVO;
import com.tiancheng.trade.order.vo.app.ChannelReportVO;
import jakarta.annotation.Resource;
import jodd.time.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @Author: likailun
 * @Description: 上报渠道 service实现
 * @Date: create in 2022/12/19 16:18
 */
@Slf4j
@Service
public class ReportChannelServiceImpl implements ReportChannelService {

    @Resource
    private ReportChannelMapper reportChannelMapper;
    @Resource
    private PlatformRequest platformRequest;
    @Resource
    private ReportCache reportCache;
    @Resource
    private ReportChannelConfigService reportChannelConfigService;
    @Resource
    private MessageProducer messageProducer;
    @Resource
    private IReportRecordService reportRecordService;

    /**
     * 平台小程序clientId
     */
    @Value(value = "${system.yyn-mini-app-client-id}")
    private String yynMiniAppClientId;
    @Value(value = "${report.tencentToken}")
    private String tencentToken;

    @Override
    public Result<ChannelReportCacheVO> report(ChannelReportVO params, String uid) {
        if (null == params || StringUtils.isEmpty(params.getUserKey())) {
            log.error("参数或用户为空");
            // 清空用户渠道缓存
            reportCache.delUserReportArg(uid);
            return Result.fail("参数异常", null);
        }
        final Optional<ChannelReportCacheVO> userReportArg = reportCache.getUserReportArg(params.getUserKey());
        if (!userReportArg.isPresent()) {
            // 清空用户渠道缓存
            reportCache.delUserReportArgByKey(params.getUserKey());
            BusinessErrorInfoEnum.REPORT_USER_CACHE_NULL.assertFail();
        }
        final ChannelReportCacheVO channelReportCacheVO = userReportArg.get();

        final ReportChannelEnum channel = getChannel(channelReportCacheVO);
        if (channel == null) {
            // 清空用户渠道缓存
            reportCache.delUserReportArgByKey(params.getUserKey());
            BusinessErrorInfoEnum.REPORT_UNKNOWN_CHANNEL.assertFail();
        }
        final List<ReportChannelConfig> reportChannelConfigs = reportChannelConfigService.queryByMainAgr(channel.getCode());

        //没有渠道配置
        if (CollectionUtils.isEmpty(reportChannelConfigs)) {
            // 清空用户渠道缓存
            reportCache.delUserReportArgByKey(params.getUserKey());
            BusinessErrorInfoEnum.REPORT_UNKNOWN_CHANNEL.assertFail();
        }
        String pageStack = params.getPageStack().replaceAll("'", "\"").replaceAll(" ", "");
        log.info("缓存的渠道配置：{},用户上报的页面栈:{}", JsonUtil.toJsonString(reportChannelConfigs), pageStack);
        final ReportRecord reportRecord = new ReportRecord();
        reportRecord.setOrderId(params.getOrderId());
        reportRecord.setMainArg(channel.getCode());
        reportRecord.setCreatedDt(LocalDateTime.now());
        reportRecord.setCreatedBy(uid);
        reportRecord.setState(1);
        for (ReportChannelConfig config : reportChannelConfigs) {
            reportRecord.setConfigId(config.getConfigId());
            final JSONArray objects = JSONObject.parseArray(config.getPageStack());
            boolean isMatching = false;
            for (Object object : objects) {
                if (object.toString().replaceAll(" ", "").equals(pageStack)) {
                    isMatching = true;
                    break;
                }
            }
            if (!isMatching) {
                // 清空用户渠道缓存
                reportCache.delUserReportArgByKey(params.getUserKey());
                reportRecord.setRemark(BusinessErrorInfoEnum.REPORT_PAGE_NOT_MATCH.getMessage());
                reportRecordService.save(reportRecord);
                return Result.fail(BusinessErrorInfoEnum.REPORT_PAGE_NOT_MATCH.getCode(), BusinessErrorInfoEnum.REPORT_PAGE_NOT_MATCH.getMessage(), null);
            }
            final String header = config.getHeader();
            Map<String,String> headers = new HashMap<>();
            if (!StringUtils.isEmpty(header)) {
                final String[] split = header.split(";");
				for (String s : split) {
					if (StringUtils.isEmpty(s)) {
						continue;
					}
					final String[] kv = s.split(":");
					headers.put(kv[0].trim(), kv[1].trim());
				}
            }
            String url = config.getApi();
            JSONObject body = null;
            switch (channel) {
                case gdt_vid:
                    // 微信广告
                    url = url.replace("<ACCESS_TOKEN>", getWechatInterfaceToken());
                    String reqBody = config.getReqBody();
                    if (StringUtils.isNotEmpty(reqBody)) {
                        final long payTime = params.getPayTime() == null ? System.currentTimeMillis() / 1000 : params.getPayTime().atZone(ZoneId.systemDefault()).toEpochSecond();
                        final BigDecimal payAmount = params.getPayAmount();
                        channelReportCacheVO.setPayAmount(payAmount);
                        channelReportCacheVO.setPayTime(DateTimeUtil.timestamp2Datetime(payTime * 1000));
                        reqBody = reqBody.replace("<gdt_vid>", MapUtils.getString(channelReportCacheVO.getArgs(), ReportChannelEnum.gdt_vid.getCode())).replace("<PAY_TIME>", payTime + "").replace("<PAY_AMOUNT_FEN>", payAmount.toString());

                        body = JSONObject.parseObject(reqBody);
                    }
                    log.info("微信广告渠道处理");
                    break;
                case qz_gdt:
                    // 腾讯广告
                    url = url.replace("<access_token>", tencentToken).replace("<timestamp>", String.valueOf(TimeUtil.toMilliseconds(LocalDateTime.now()))).replace("<nonce>", UUID.randomUUID().toString().replace("-", ""));
                    String req = config.getReqBody();
                    if (StringUtils.isNotEmpty(req)) {
                        final long payTime = params.getPayTime() == null ? System.currentTimeMillis() / 1000 : params.getPayTime().atZone(ZoneId.systemDefault()).toEpochSecond();
                        final BigDecimal payAmount = params.getPayAmount();
                        channelReportCacheVO.setPayAmount(payAmount);
                        channelReportCacheVO.setPayTime(DateTimeUtil.timestamp2Datetime(payTime * 1000));
                        req = req.replace("<qz_gdt>", MapUtils.getString(channelReportCacheVO.getArgs(), ReportChannelEnum.qz_gdt.getCode())).replace("<PAY_TIME>", payTime + "").replace("<PAY_AMOUNT_FEN>", payAmount.toString());

                        body = JSONObject.parseObject(req);
                    }
                    log.info("腾讯广告（非微信）渠道处理");
                    break;
                case channel_track_key:
                    // 神策
                    System.out.println();
                    break;
                default:
                    log.error("未知的渠道上报");
            }
			Map r = platformRequest.getHttpRequestUtils().post(url).addBody(body).addHeader(headers).execute(Map.class);


            log.info("上报渠道返回：{}", JsonUtil.toJsonString(r));
            if (r != null && (r.containsKey("errcode") && MapUtils.getInteger(r, "errcode").equals(0) // 微信渠道上报结果
                    || r.containsKey("code") && MapUtils.getInteger(r, "code").equals(0))// 腾讯广告上报结果
            ) {
                // 上报成功删除用户缓存参数
                reportCache.delUserReportArgByKey(params.getUserKey());
                final Map<String, Object> p = new HashMap<>();
                p.put("uid", uid);
                p.put("content_name", channel.getCode());
                p.put("content_source", MapUtils.getString(channelReportCacheVO.getArgs(), channel.getCode()));
                p.put("column_name", channelReportCacheVO.getColumnName());
                p.put("column_id", channelReportCacheVO.getColumnId());
                p.put("pay_amount", channelReportCacheVO.getPayAmount());
                p.put("pay_time", channelReportCacheVO.getPayTime());
                p.put("order_id", params.getOrderId());
                reportRecord.setState(0);
                //messageProducer.tallyChannelReport(p);
            }
            String msg = "";
            if (r != null) {
                msg = r.containsKey("errmsg") ? MapUtils.getString(r, "errmsg") : MapUtils.getString(r, "message");
            }
            reportRecord.setRemark(msg);
            reportRecordService.save(reportRecord);
            return Result.success(channelReportCacheVO);
        }
        // 清空用户渠道缓存
        reportCache.delUserReportArgByKey(params.getUserKey());
        return Result.fail("上报异常", null);
    }

    /**
     * 判断是哪个渠道
     *
     * @param params
     * @return
     */
    public ReportChannelEnum getChannel(ChannelReportCacheVO params) {
        for (ReportChannelEnum item : ReportChannelEnum.values()) {
            if (MapUtils.isNotEmpty(params.getArgs()) && params.getArgs().containsKey(item.getCode()) && StringUtils.isNotEmpty(MapUtils.getString(params.getArgs(), item.getCode()))) {
                return item;
            }
        }
        return null;
    }

    public void actionHandle(String url, Header[] headers) {

    }

    @Override
    public void add(ReportChannel channel) {
        final QueryWrapper<ReportChannel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("main_arg", channel.getMainArg());
        queryWrapper.eq("is_delete", false);
        final List<ReportChannel> reportChannelConfigs = reportChannelMapper.selectList(queryWrapper);
        BusinessErrorInfoEnum.REPORT_REPEAT_RECORD.assertIsTrue(CollectionUtils.isEmpty(reportChannelConfigs));
        channel.setChannelId(CommonUtil.uuid());
        // 默认启用
        channel.setState(0);
        // 默认不删除
        channel.setIsDelete(0);
        channel.setCreatedDt(LocalDateTime.now());
        reportChannelMapper.insert(channel);
        reportCache.delChannel();
    }

    @Override
    public void update(ReportChannel channel) {
        final ReportChannel reportChannel = reportChannelMapper.selectById(channel.getId());
        if (null == reportChannel) {
            throw new BusinessException(ArgumentErrorInfoEnum.VALID_ERROR, null, "未查询到记录");
        }
        reportChannel.setLastUpdDt(LocalDateTime.now());
        reportChannelMapper.updateById(channel);
        reportCache.delChannel();
    }

    @Override
    public void setState(Long id, Integer state) {
        final ReportChannel reportChannel = reportChannelMapper.selectById(id);
        if (null == state || state > 1 || null == reportChannel) {
            throw new BusinessException(ArgumentErrorInfoEnum.VALID_ERROR, null, "参数异常，未查询到记录");
        }
        if (state.equals(reportChannel.getState())) {
            return;
        }
        reportChannel.setState(state);
        reportChannelMapper.updateById(reportChannel);
        reportCache.delChannel();
    }

    @Override
    public void delete(Long id) {
        final ReportChannel reportChannel = reportChannelMapper.selectById(id);
        if (null == reportChannel) {
            throw new BusinessException(ArgumentErrorInfoEnum.VALID_ERROR, null, "参数异常，未查询到记录");
        }
        if (reportChannel.getIsDelete()==1) {
            return;
        }
        reportChannel.setIsDelete(1);
        reportChannelMapper.updateById(reportChannel);
        reportCache.delChannel();
    }

    @Override
    public PageInfo<ReportChannel> queryBankPage(QueryReportChannelVO params) {
        QueryWrapper<ReportChannel> conditions = new QueryWrapper<>();
        if (params.getIsDelete() != null) {
            conditions.eq("is_delete", params.getIsDelete());
        }
        if (null != params.getState()) {
            conditions.eq("state", params.getState());
        }
        if (StringUtils.isNotEmpty(params.getMainArg())) {
            conditions.eq("main_arg", params.getMainArg());
        }
        return reportChannelMapper.find(conditions, params.getCurrentPage(), params.getPageSize());
    }

    @Override
    public List<ReportChannel> queryByIds(Set<Long> ids) {
        QueryWrapper<ReportChannel> conditions = new QueryWrapper<>();
        conditions.in("id", ids);
        return reportChannelMapper.selectList(conditions);
    }

    @Override
    public void clearCache(String uid) {
        reportCache.delUserReportArg(uid);
    }

    @Override
    public void clearChannelCache(String mainArg) {
        reportCache.delChannelConfig(mainArg);
        log.info("删除缓存的渠道信息：{}", mainArg);
    }

    @Override
    public List<ReportChannel> queryReportChannel(Integer state, boolean isDelete) {
        final QueryWrapper<ReportChannel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("state", state);
        queryWrapper.eq("is_delete", isDelete);
        return reportChannelMapper.selectList(queryWrapper);
    }

    @Override
    public List<ReportRecord> queryReportRecord(String orderId) {
        return reportRecordService.queryByOrderId(orderId);
    }


    /**
     * 去微信小程序接口调用token
     *
     * @return
     */
    public String getWechatInterfaceToken() {
        final Optional<String> wechatToken = reportCache.getWechatToken(yynMiniAppClientId);
        if (wechatToken.isPresent()) {
            return wechatToken.get();
        }
        // 地址直接撸死，不需要区分环境，没luan用
		Result tokenResult = platformRequest.getHttpRequestUtils().get("https://mid.ybsjyyn.com/auth/thirdApplication/getWeChatAccessToken?app_id=" + yynMiniAppClientId).execute(Result.class);
        if (tokenResult.getRet() == 0) {
            Map<String, Object> dataMap = (Map<String, Object>) tokenResult.getData();
            final Long expiresIn = MapUtils.getLong(dataMap, "expires_in");
            //提前5分钟过期
            final long expiresSecond = expiresIn - 60;
            if (expiresSecond <= 0) {
                return MapUtils.getString(dataMap, "access_token");
            }
            reportCache.cacheWechatToken(yynMiniAppClientId, MapUtils.getString(dataMap, "access_token"), expiresSecond);
            return MapUtils.getString(dataMap, "access_token");
        }
        return null;
    }

    private Header getTokenHeader() {
        return new BasicHeader("token", platformRequest.getAccessToken());
    }

    public void getUserActionSetId() {
        final Map<String,String> params = new HashMap<>();
        params.put("type", "WEB");
        params.put("name", "pay_report_test");
        params.put("description", "支付上报测试");
        final Map<String,String> basicHeader = new HashMap<>();
		basicHeader.put("Content-Type","application/json");
		final Map tokenResult  = platformRequest.getHttpRequestUtils().post( "https://api.weixin.qq.com/marketing/user_action_sets/add?version=v1.0&access_token=" + getWechatInterfaceToken())
				.addBody(params)
				.addHeader(basicHeader)
				.execute(Map.class);
        if (tokenResult != null && tokenResult.containsKey("errcode") && MapUtils.getInteger(tokenResult, "errcode").equals(0)) {
            log.info("上报成功咯。。。。。{}", JsonUtil.toJsonString(tokenResult));
        }
    }

}
